﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace uam_fps_game.Gfx
{
    internal class VisibleAreaManager
    {
        internal void PrepareVisibleAreaData(VisibleAreaData outData, VisualSceneData sceneData)
        {
            BoundingFrustum frustum = new BoundingFrustum(sceneData.ViewMatrix * sceneData.ProjectionMatrix);

            outData.Clear();

            List<Light> lights = sceneData.Lights;
            List<Billboard> billboards = sceneData.Billboards;
            List<ModelInstance> models = sceneData.Models;
            List<ParticleSystem> particlesystems = sceneData.ParticleSystems;
            for (int i = 0; i < lights.Count; ++i)
            {
                lights[i].UpdateSpatialParams();
                lights[i].UpdateBoundingSphere();
                outData.Lights.Add(lights[i]);
            }
            if (sceneData.MainLightEnabled)
            {
                outData.Lights.Add(sceneData.MainLight);
            }

            for (int i = 0; i < models.Count; i++)
            {
                ModelInstance obj = models[i];
                obj.UpdateBoundingSphere();

                if (!frustum.Intersects(obj.WorldSpaceBoundingSphere))
                    continue;

                VisibleModelData visibleObj = new VisibleModelData();
                visibleObj.Model = obj.ModelObject;
                visibleObj.WorldMatrix = obj.WorldMatrix;
                visibleObj.Visible = obj.Visible;

                visibleObj.LightsNum = 0;

                visibleObj.LightIndices = new int[VisibleAreaData.MAX_LIGHTS];
                visibleObj.LightInfluences = new float[VisibleAreaData.MAX_LIGHTS];

                int objLightIndex = 0;

                // uglyuglyugly hack...
                int maxLightsToTest = outData.Lights.Count;
                if (sceneData.MainLightEnabled)
                {
                    visibleObj.LightIndices[objLightIndex] = outData.Lights.Count - 1;
                    visibleObj.LightInfluences[objLightIndex] = 100.0f;
                    objLightIndex++;
                    maxLightsToTest = outData.Lights.Count - 1;
                }

                for (int k = 0; k < maxLightsToTest; ++k)
                {
                    if (lights[k].WorldSpaceBoundingSphere.Intersects(obj.WorldSpaceBoundingSphere))
                    {
                        if (objLightIndex == VisibleAreaData.MAX_LIGHTS)
                            break;
                        visibleObj.LightIndices[objLightIndex] = k;
                        visibleObj.LightInfluences[objLightIndex] = 1.0f; // hardcoded for now
                        objLightIndex++;
                    }
                }
                visibleObj.LightsNum = objLightIndex;

                outData.Models.Add(visibleObj);
            }

            for (int i = 0; i < billboards.Count; i++)
            {
                Billboard obj = billboards[i];
                obj.UpdateBoundingSphere();

                if (frustum.Intersects(obj.WorldSpaceBoundingSphere))
                    outData.Billboards.Add(obj);
            }

            for (int i = 0; i < particlesystems.Count; i++)
            {
                ParticleSystem obj = particlesystems[i];
                obj.UpdateBoundingSphere();

                //if (frustum.Intersects(obj.WorldSpaceBoundingSphere))
                    outData.ParticleSystems.Add(obj);
            }
        }
    }
}
